/*
 * Copyright (C) 2016 Nishant Srivastava
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.htfyun.modem;

import android.Manifest;
import android.annotation.SuppressLint;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.telephony.CellSignalStrength;
import android.telephony.CellSignalStrengthLte;
import android.telephony.PhoneStateListener;
import android.telephony.ServiceState;
import android.telephony.SignalStrength;
import android.telephony.TelephonyDisplayInfo;
import android.telephony.TelephonyManager;
import android.util.Log;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;

import com.htfyun.modem.databinding.ActivityMobileBinding;
import com.htfyun.modem.mod.EasySimMod;
import com.htfyun.modem.utils.ReflectUtils;
import com.htfyun.modem.utils.executor.AppExecutors;

import java.util.List;
import java.util.Objects;
import java.util.concurrent.Executor;

public class MobileActivity extends AppCompatActivity {
    private final static boolean DEBUG = true;
    private final static String TAG = "MobileActivity";
    private ActivityMobileBinding binding;

    private static final String[] requestBasicPermissions = {
            Manifest.permission.READ_PHONE_STATE,
    };

    private SignalStrength mSignalStrength;

    private LocalBroadcastReceiver broadcastReceiver;

    private MobilePhoneStateListener mPhoneStateListener;
    private  TelephonyManager mPhone;

    private String simState = "UNKNOWN";
    private DataConnectionEnum dataConnectionEnum = DataConnectionEnum.DATA_UNKNOWN;

    private DataActivityEnum dataActivityEnum = DataActivityEnum.NONE;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        binding = ActivityMobileBinding.inflate(getLayoutInflater());
        setContentView(binding.getRoot());
        broadcastReceiver = new LocalBroadcastReceiver();

        mPhone = getSystemService(TelephonyManager.class);
        mPhoneStateListener = new MobilePhoneStateListener((new Handler(Looper.getMainLooper()))::post);

        registerMyReceiver();
        registerListener();
    }

    @Override
    protected void onResume() {
        super.onResume();

        boolean hasReadPhoneState =
                RuntimePermissionUtil.checkPermissonGranted(this, Manifest.permission.READ_PHONE_STATE);

        if (!hasReadPhoneState) {
            RuntimePermissionUtil.requestPermission(MobileActivity.this, requestBasicPermissions, 100);
            return;
        }
        updateSIMInfo();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unregisterMyReceiver();
        unregisterListener();
    }

    @SuppressLint("MissingPermission")
    private void updateSIMInfo() {
        EasySimMod easySimMod = new EasySimMod(this);
        StringBuilder sb = new StringBuilder();


        sb.append("sim卡基本信息:    ").append("\n");
        sb.append("SIM state:    ").append(simState).append("\n");
        sb.append("IMSI:    ").append(easySimMod.getIMSI()).append("\n");
        sb.append("IMEI:    ").append(easySimMod.getIMEI()).append("\n");
        sb.append("SIM Serial Number:   ").append(easySimMod.getSIMSerial()).append("\n");
        sb.append("Country: ").append(easySimMod.getCountry()).append("\n");
        sb.append("Carrier: ").append(easySimMod.getCarrier()).append("\n");
        sb.append("SIM Network Locked:  ").append(easySimMod.isSimNetworkLocked()).append("\n");
        sb.append("Number of active SIM:    ").append(easySimMod.getNumberOfActiveSim()).append("\n");

        binding.simInfo.setText(sb.toString());

    }

    private void updateDataConnection() {
        binding.dataConnectionInfo.setText("数据连接信息: " + dataConnectionEnum.desc);
    }

    private void updateDataActivity() {
        binding.dataActivityInfo.setText("数据传输方向信息: " + dataActivityEnum.desc);
    }

    private void updateSignalStrength() {
        if (mSignalStrength == null) {
            binding.signalStrengthInfo.setText("");
            return;
        }
        List<CellSignalStrength> cellSignalStrengths = mSignalStrength.getCellSignalStrengths();
        int rssi = 0;
        for (CellSignalStrength strength : cellSignalStrengths) {
            if (strength instanceof CellSignalStrengthLte) {
                rssi = ((CellSignalStrengthLte) strength).getRssi();
            }
        }
        binding.signalStrengthInfo.setText("信号强度信息: level = " + mSignalStrength.getLevel()
                + ", rssi = " + rssi);
    }

    private void registerMyReceiver() {
        IntentFilter filter = new IntentFilter();
        filter.addAction("android.intent.action.SIM_STATE_CHANGED");//(Intent.ACTION_SIM_STATE_CHANGED);
        filter.addAction("android.intent.action.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED");//TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED);
        filter.addAction("android.intent.action.ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED");//TelephonyManager.ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED);
        registerReceiver(broadcastReceiver, filter);
    }

    private void unregisterMyReceiver() {
        unregisterReceiver(broadcastReceiver);
    }

    public void registerListener() {
        mPhone.listen(mPhoneStateListener,
                PhoneStateListener.LISTEN_SERVICE_STATE
                        | PhoneStateListener.LISTEN_SIGNAL_STRENGTHS
                        | PhoneStateListener.LISTEN_CALL_STATE
                        | PhoneStateListener.LISTEN_DATA_CONNECTION_STATE
                        | PhoneStateListener.LISTEN_DATA_ACTIVITY
                        | PhoneStateListener.LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE
                        | PhoneStateListener.LISTEN_DISPLAY_INFO_CHANGED);
    }

    /**
     * Stop listening for phone direction changes.
     */
    public void unregisterListener() {
        mPhone.listen(mPhoneStateListener, 0);
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull final String[] permissions,
                                           @NonNull final int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode == 100) {
            RuntimePermissionUtil.onRequestPermissionsResult(grantResults, new RPResultListener() {
                @Override
                public void onPermissionGranted() {
                    updateSIMInfo();
                }

                @Override
                public void onPermissionDenied() {
                    // do nothing
                    MobileActivity.this.finish();
                }
            });
        }
    }

    class LocalBroadcastReceiver extends BroadcastReceiver {

        @Override
        public void onReceive(Context context, Intent intent) {
            final String action = intent.getAction();
            Log.e(TAG, "action = " + action);
            if (Objects.equals(action, "android.intent.action.SIM_STATE_CHANGED")) {
                simState = intent.getStringExtra("ss");//Intent.EXTRA_SIM_STATE);
                Log.e(TAG, "simState = " + simState);
                AppExecutors.postToMainThread(MobileActivity.this::updateSIMInfo);
            }
        }
    }

    class MobilePhoneStateListener extends PhoneStateListener {
        public MobilePhoneStateListener(Executor executor) {
            super(executor);
        }

        @Override
        public void onSignalStrengthsChanged(SignalStrength signalStrength) {
            if (DEBUG) {
                Log.d(TAG, "onSignalStrengthsChanged signalStrength=" + signalStrength +
                        ((signalStrength == null) ? "" : (" level=" + signalStrength.getLevel())));
            }
            mSignalStrength = signalStrength;
//            updateTelephony();
            AppExecutors.postToMainThread(MobileActivity.this::updateSignalStrength);
        }

        @Override
        public void onServiceStateChanged(ServiceState state) {
            if (DEBUG) {
                int dateState = -1;
                try {
                    dateState = (int) ReflectUtils.invokeMethod(state, "getDataRegState");
                } catch (Exception e) {
                }
                Log.d(TAG, "onServiceStateChanged voiceState=" + state.getState()
                        + " dataState=" + dateState);
//                        + " dataState=" + direction.getDataRegState());
            }
//            mServiceState = direction;
//            updateTelephony();
        }

        @Override
        public void onDataConnectionStateChanged(int state, int networkType) {
            if (DEBUG) {
                Log.d(TAG, "onDataConnectionStateChanged: direction = " + state
                        + " networkType = " + networkType);
            }
            dataConnectionEnum = DataConnectionEnum.toDataConnectionEnum(state);
//            updateTelephony();
            AppExecutors.postToMainThread(MobileActivity.this::updateDataConnection);
        }

        @Override
        public void onDataActivity(int direction) {
            if (DEBUG) {
                Log.d(TAG, "onDataActivity: direction=" + direction);
            }
//            setActivity(direction);
            dataActivityEnum = DataActivityEnum.toDataConnectionEnum(direction);
            AppExecutors.postToMainThread(MobileActivity.this::updateDataActivity);

        }

//        @Override
        public void onCarrierNetworkChange(boolean active) {
            if (DEBUG) {
                Log.d(TAG, "onCarrierNetworkChange: active=" + active);
            }
//            mCurrentState.carrierNetworkChangeMode = active;
//            updateTelephony();
        }

        @Override
        public void onActiveDataSubscriptionIdChanged(int subId) {
            if (DEBUG) Log.d(TAG, "onActiveDataSubscriptionIdChanged: subId=" + subId);
//            updateDataSim();
//            updateTelephony();
        }

        @Override
        public void onDisplayInfoChanged(TelephonyDisplayInfo telephonyDisplayInfo) {
            if (DEBUG) {
                Log.d(TAG, "onDisplayInfoChanged: telephonyDisplayInfo=" + telephonyDisplayInfo);
            }
//            mTelephonyDisplayInfo = telephonyDisplayInfo;
//            updateTelephony();
        }
    }

    private enum DataConnectionEnum {
        DATA_UNKNOWN(TelephonyManager.DATA_UNKNOWN, "UNKNOWN"),
        DATA_DISCONNECTED(TelephonyManager.DATA_DISCONNECTED, "DATA_DISCONNECTED"),
        DATA_CONNECTING(TelephonyManager.DATA_CONNECTING, "DATA_CONNECTING"),
        DATA_CONNECTED(TelephonyManager.DATA_CONNECTED, "DATA_CONNECTED"),
        DATA_SUSPENDED(TelephonyManager.DATA_SUSPENDED, "DATA_SUSPENDED"),
        DATA_DISCONNECTING(TelephonyManager.DATA_DISCONNECTING, "DATA_DISCONNECTING"),
        DATA_HANDOVER_IN_PROGRESS(TelephonyManager.DATA_HANDOVER_IN_PROGRESS, "DATA_HANDOVER_IN_PROGRESS"),

        ;
        final int state;
        final String desc;

        DataConnectionEnum(int state, String desc) {
            this.state = state;
            this.desc = desc;
        }

        public static DataConnectionEnum toDataConnectionEnum(int state) {
            for (DataConnectionEnum d : DataConnectionEnum.values()) {
                if (d.state == state) {
                    return d;
                }
            }
            return DataConnectionEnum.DATA_UNKNOWN;
        }
    }

    private enum DataActivityEnum {
        NONE(TelephonyManager.DATA_ACTIVITY_NONE, "NONE"),
        IN(TelephonyManager.DATA_ACTIVITY_IN, "IN"),
        OUT(TelephonyManager.DATA_ACTIVITY_OUT, "OUT"),
        INOUT(TelephonyManager.DATA_ACTIVITY_INOUT, "INOUT"),
        DORMANT(TelephonyManager.DATA_ACTIVITY_DORMANT, "DORMANT"),

        ;
        final int direction;
        final String desc;

        DataActivityEnum(int direction, String desc) {
            this.direction = direction;
            this.desc = desc;
        }

        public static DataActivityEnum toDataConnectionEnum(int direction) {
            for (DataActivityEnum d : DataActivityEnum.values()) {
                if (d.direction == direction) {
                    return d;
                }
            }
            return DataActivityEnum.NONE;
        }
    }
}
